/**
 * 
 */
package net.looker.data;

import java.io.IOException;
import java.util.logging.Logger;

import net.looker.config.ConfigManager;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.LockObtainFailedException;
import org.mira.lucene.analysis.IK_CAnalyzer;
import org.mira.lucene.analysis.MIK_CAnalyzer;

import com.chenlb.mmseg4j.analysis.ComplexAnalyzer;


/**
 * Lucence数据驱动
 * 因为MSYQL数据库全文索引的效果不是很好，因此用Lucence为新闻作索引，提高效率和准确性
 * 这个驱动是一直打开索引文件进行操作，主要是对索引操作频繁时使用，如导入新闻时
 * @author solosky
 *
 */
public class Lucene2DataDriver  extends DataDriver 
{
	/**
	 * Lucene索引写对象
	 */
	private IndexWriter indexWriter;
	
	/**
	 * 日志记录对象
	 */
	private  Logger logger;

	public Lucene2DataDriver()
	{
		logger = Logger.getLogger("looker");
		indexWriter = openIndex();
		registerShutdownHook();
	}
	/* (non-Javadoc)
	 * @see net.looker.news.data.driver.DataDriver#add(net.looker.news.message.News)
	 */
	@Override
	public  synchronized boolean add(News news)
	{
		//新建一个文档，一个文档对应一个页面
		Document doc = new Document();
		
		//字段，和数据库的概念相似
		//建立一个字段的参数分别是 字段名， 内容， 是否保存内容， 是否分词
		String siteStr  = news.getCategory().getSiteConfig().get("site.title");
		String cateStr  = news.getCategory().getTitle();
		String dateStr  = Long.toString(news.getDate().getTime());
		
		Field hash    = new Field("newshash",  news.getNewsHash(),  Field.Store.YES, Field.Index.ANALYZED);
		Field title   = new Field("title",     news.getTitle(),     Field.Store.YES, Field.Index.ANALYZED);
		Field intro   = new Field("intro",     news.getIntro(),     Field.Store.YES, Field.Index.ANALYZED);
		Field author  = new Field("author",    news.getAuthor(),    Field.Store.YES, Field.Index.ANALYZED);
		Field site    = new Field("site",      siteStr,             Field.Store.YES, Field.Index.ANALYZED);
		Field cate    = new Field("category",  cateStr,             Field.Store.YES, Field.Index.ANALYZED);
		Field url     = new Field("url",       news.getUrl(),       Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field date    = new Field("date",      dateStr,             Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field thumb   = new Field("thumb",     news.getThumb(),     Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field media   = new Field("media",     Integer.toString(news.getMedia()),     Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field image   = new Field("image",     Integer.toString(news.getImage()),     Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field video   = new Field("video",     Integer.toString(news.getVideo()),     Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field audio   = new Field("audio",     Integer.toString(news.getAudio()),     Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field zip    = new Field("zip",       Integer.toString(news.getZip()),       Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field doc1    = new Field("doc",       Integer.toString(news.getDoc()),       Field.Store.YES, Field.Index.NOT_ANALYZED);
		Field other   = new Field("other",     Integer.toString(news.getOther()),     Field.Store.YES, Field.Index.NOT_ANALYZED);

		//将上面的字段添加到文档中
		doc.add(hash);
		doc.add(title);
		doc.add(intro);
		doc.add(author);
		doc.add(site);
		doc.add(cate);
		doc.add(url);
		doc.add(date);
		doc.add(thumb);
		doc.add(media);
		doc.add(image);
		doc.add(video);
		doc.add(audio);
		doc.add(zip);
		doc.add(doc1);
		doc.add(other);
		
		//添加文档
		try {
			indexWriter.addDocument(doc);
			indexWriter.flush();
		} catch (CorruptIndexException e) {
			logger.warning("Lucene数据驱动：添加出错->索引文件格式错误:"+e.getMessage());
			return false;
		} catch (IOException e) {
			logger.warning("Lucene数据驱动：添加出错->索引文件读取错误:"+e.getMessage());
			return false;
		}
		return true;
	}
	
	
	/* (non-Javadoc)
	 * @see net.looker.data.DataDriver#delete(net.looker.data.News)
	 */
	@Override
	public  synchronized boolean delete(News news)
	{
		Query query = new TermQuery( new Term("newshash",news.getNewsHash()));
		try {
			indexWriter.deleteDocuments(query);
		} catch (CorruptIndexException e) {
			logger.warning("Lucene数据驱动：删除出错->索引文件格式错误:"+e.getMessage());
			return false;
		} catch (IOException e) {
			logger.warning("Lucene数据驱动：删除出错->索引文件读取错误:"+e.getMessage());
			return false;
		}
		return true;
	}
	

	/* (non-Javadoc)
	 * @see net.looker.data.DataDriver#update(net.looker.data.News)
	 */
	@Override
	public boolean update(News news)
	{
		// TODO Auto-generated method stub
		return false;
	}
	
	/**
	 * 打开索引
	 * @return
	 */
	private IndexWriter openIndex()
	{
		IndexWriter indexWriter = null;
		String indexDir = ConfigManager.getInstance().getLookerConfig().get("data.lucene.indexDir");
		//初始化分词器
		String dicDir = ConfigManager.getInstance().getLookerConfig().get("data.lucene.dicDir");
		try {
			indexWriter   = new IndexWriter(indexDir,  new ComplexAnalyzer(dicDir), false, IndexWriter.MaxFieldLength.LIMITED);
		} catch (CorruptIndexException e) {
			logger.warning("Lucene数据驱动：索引文件错误->"+e.getMessage());
		} catch (LockObtainFailedException e) {
			logger.warning("Lucene数据驱动：索引已被锁->"+e.getMessage());
		} catch (IOException e) {
			logger.warning("Lucene数据驱动：索引文件读取错误->"+e.getMessage());
		}finally{
		}
		return indexWriter;
	}
	
	/**
	 * 注册结束关闭操作
	 */
	private void registerShutdownHook()
	{
		Runtime.getRuntime().addShutdownHook(new Thread(
				new Runnable(){
					public void run(){
						try {
							indexWriter.optimize();
							indexWriter.close();
						} catch (CorruptIndexException e) {
							logger.warning("索引器关闭时错误:"+e.getMessage());
						} catch (IOException e) {
							logger.warning("索引器关闭时错误:"+e.getMessage());
						}
					}
				}
		
		));
	}
}
